/*
 * debounce.c
 *
 * Created: 2013-08-26 15:54:21
 *  Author: Piotr
 */ 

#include "board.h"

#define KEY_2	2
#define KEY_1	1
#define KEY_SW	0


#define KEY_ALL	            ((1 << KEY_1) | (1 << KEY_2) | (1 << KEY_SW) )
#define LONG_MASK           ((1 << KEY_1) | (1 << KEY_2) | (1 << KEY_SW) )
#define REPEAT_MASK         ((1 << KEY_1) | (1 << KEY_2) | (1 << KEY_SW) )
#define LONG_REPEAT_MASK    0 //((1 << KEY_1) | (1 << KEY_2) | (1 << KEY_SW) )
#define LONG_REPEAT_SP_MASK 0 //((1 << KEY_1) | (1 << KEY_2) | (1 << KEY_SW) )

#define REPEAT_START    70  // after 700ms
#define REPEAT_NEXT     15  // every 150ms
#define REPEAT_SPEED_1  20  // every 200ms
#define REPEAT_SPEED_2   8  // every  80ms
#define REPEAT_SPEED_3   1  // every  10ms


/*
 * Module global variable, informs the main programm when a key is pressed.
 * This variable must be declared 'volatile, since it is accessed from
 * both interrupt und main loop.
 */

volatile uint8_t key_press=0;	   
volatile uint8_t key_state=0;	// debounced and inverted key state: bit = 1: key pressed
volatile uint8_t key_rpt=0;	// key long press and repeat

volatile uint8_t SWITCH1;
volatile uint8_t SWITCH2;


uint8_t key_long = 0;		// key long press
uint8_t key_lrpt = 0;		// key long press and repeat
uint8_t key_rpts = 0;		// key long press and speed repeat
uint8_t repeat_speed = 0;

volatile uint8_t sec_cnt=0;	// seconds tick

///////////////////////////////////////////////////////////////////
//
// check if a key has been pressed. Each pressed key is reported
// only once
//
uint8_t get_key_press( uint8_t key_mask )
{
	cli();                                          // read and clear atomic !
	key_mask &= key_press;                          // read key(s)
	key_press ^= key_mask;                          // clear key(s)
	sei();
	return key_mask;
}

///////////////////////////////////////////////////////////////////
//
// check if a key has been pressed long enough such that the
// key repeat functionality kicks in. After a small setup delay
// the key is reported beeing pressed in subsequent calls
// to this function. This simulates the user repeadiately
// pressing and releasing the key.
//
uint8_t get_key_rpt( uint8_t key_mask )
{
	cli();                                          // read and clear atomic !
	key_mask &= key_rpt;                            // read key(s)
	key_rpt ^= key_mask;                            // clear key(s)
	sei();
	return key_mask;
}

///////////////////////////////////////////////////////////////////
//
uint8_t get_key_short( uint8_t key_mask )
{
	cli();                                          // read key state and key press atomic !
	return get_key_press( ~key_state & key_mask );
}

///////////////////////////////////////////////////////////////////
//
uint8_t get_key_long( uint8_t key_mask )
{
	cli();
	key_mask &= key_long;	// read key(s)
	key_long ^= key_mask;	// clear key(s)
	return get_key_press( get_key_rpt( key_mask ));
}



//*****************************************************************************
// 
uint8_t get_key_long_rpt (uint8_t key_mask)
{
	cli();
	key_mask &= key_lrpt;	// read key(s)
	key_lrpt ^= key_mask;	// clear key(s)
	return get_key_rpt (~key_press^key_mask);
}	

//*****************************************************************************
//
uint8_t get_key_long_rpt_sp (uint8_t key_mask, uint8_t key_speed)
{
	uint8_t sreg = SREG;

	// disable all interrupts
	cli();

	key_mask &= key_rpts;	// read key(s)
	key_rpts ^= key_mask;	// clear key(s)

	repeat_speed = key_speed;

	SREG = sreg;	// restore status register

	return key_mask;
}


//*****************************************************************************
//
SIGNAL ( TIMER3_COMPA_vect )
{
static uint8_t ct0, ct1, rpt;      // holds two bit counter for each key
static uint8_t k_time_l = 0;
static uint8_t k_time_r = 0;
static uint8_t k_time_lr = 0;
static uint8_t k_time_rs = 0;
uint8_t i; 
static uint8_t sw2_cnt=0, sw1_cnt=0;
static uint8_t sw2_hold=0, sw1_hold=0;
/*
* read current state of keys (active-low),
* clear corresponding bit in i when key has changed
*/
//	i = key_state ^ (( ~PINF  & 0x01 ) | (( ~PINA & 0b00001100 ) >> 1 ));         // key changed ? 
	i = key_state ^ (( ~PINF  & 0x01 ) | (( ~SW_PIN & ( _BV(SW1) | _BV(SW2) ) ) >> 1 ) );         // key changed ? 
//	~SW_PORT & ( (_BV( SW1 ) | _BV(SW2 ) ) 
/* 
* ct0 and ct1 form a two bit counter for each key,  
* where ct0 holds LSB and ct1 holds MSB
* After a key is pressed longer than four times the
* sampling period, the corresponding bit in key_state is set
*/
	ct0 = ~( ct0 & i );			// reset or count ct0
	ct1 = ct0 ^ ( ct1 & i );	    // reset or count ct1  
	i &= ( ct0 & ct1 );			    // count until roll over ?
	key_state ^= i;			    // then toggle debounced state
  
/*
* To notify main program of pressed key, the correspondig bit
* in global variable key_press is set.
* The main loop needs to clear this bit
*/
	key_press |= ( key_state & i );	// 0->1: key press detect
  
	if ( !(key_state & ( 1 << KEY_2 ) ) ) {
		if ( !sw2_hold ) {
			SWITCH2 = 0;
			sw2_cnt = 0;
		}
		else sw2_hold--;
	}
	else {
		sw2_hold = 20;
		if ( sw2_cnt < 250 ) sw2_cnt++;
		if ( sw2_cnt < 100 ) SWITCH2 = 1;
			else if( sw2_cnt < 249 )  SWITCH2 = 2;
				else SWITCH2 = 3;
		
	} 
	
	if ( !(key_state & ( 1 << KEY_1 ) ) ) {
		if ( !sw1_hold ) {
			SWITCH1 = 0;
			sw1_cnt = 0;
		}
		else sw1_hold--;
	}
	else {
		sw1_hold = 20;
		if ( sw1_cnt < 250 ) sw1_cnt++;
		if ( sw1_cnt < 100 ) SWITCH1 = 1;
			else if( sw1_cnt < 249 )  SWITCH1 = 2;
				else SWITCH1 = 3;
		
	}


	//--------------------------------------------------------------
	if ((key_state & LONG_MASK) == 0)			// check long key function
		k_time_l = REPEAT_START;				// start delay

	if (--k_time_l == 0)						// long countdown
		key_long |= (key_state & LONG_MASK);

	//--------------------------------------------------------------
	if ((key_state & REPEAT_MASK) == 0)			// check repeat function
		k_time_r = 1;							// kein delay

	if (--k_time_r == 0)
	{
		k_time_r = REPEAT_NEXT;					// repeat delay
		key_rpt |= (key_state & REPEAT_MASK);
	};

//	--------------------------------------------------------------
	//if ((key_state & LONG_REPEAT_MASK) == 0)	// check repeat function
		//k_time_lr = REPEAT_START;				// start delay
//
	//if (--k_time_lr == 0)
	//{
		//k_time_lr = REPEAT_NEXT;				// repeat delay
		//key_lrpt |= (key_state & LONG_REPEAT_MASK);
	//}
//
	//--------------------------------------------------------------
	//if ((key_state & LONG_REPEAT_SP_MASK) == 0)	// check repeatX function
		//k_time_rs = REPEAT_START;				// start delay
//
	//if (--k_time_rs == 0)						// repeat countdown
	//{
		//if (repeat_speed == 1)
		//{
			//k_time_rs = REPEAT_SPEED_1;
			//key_rpts |= (key_state & LONG_REPEAT_SP_MASK);
		//}
		//else if (repeat_speed == 2)
		//{
			//k_time_rs = REPEAT_SPEED_2;
			//key_rpts |= (key_state & LONG_REPEAT_SP_MASK);
		//}
		//else if (repeat_speed == 3)
		//{
			//k_time_rs = REPEAT_SPEED_3;
			//key_rpts |= (key_state & LONG_REPEAT_SP_MASK);
		//}
	//}
//////////////////////////////////////////////////////////////////////////
//
//////////////////////////////////////////////////////////////////////////

	if ( ++sec_cnt == 50 ) {
		sec_cnt = 0;
		LED ^= _BV( LED3 );
	}
}


